# 利用tailhead软件包跟踪文件变化
# 解析log文件，上传到thingsboard

import tailhead
# 字符串解析
import parse
# 时间包
import datetime
import os
import time
import regex as re
from math import sin,isnan

# 调用客户端
from thingsboard_gateway.tb_client.tb_device_mqtt import TBDeviceMqttClient

# 用于自动生成命令行
import fire

# 输出log，便于调试
import logging

def main(host='test2.bj-jiashi.com',
        port=10006,
        token='SP2', 
        delay_time=0.5, 
        target_log_file='sub3_SP2_simulator.py.test.log',
        log_level = 'INFO'):
    # 初始化
    logging.basicConfig(level = getattr(logging,log_level.upper(),logging.INFO)) # 默认info
    file_base_name = os.path.basename(__file__)
    logger = logging.getLogger(file_base_name)

    # 分隔符
    sep = '\t'
    # 列名
    ## 33个
    header = 'Time (sec)	Sample Flow Set (vccm)	Sample Flow LFE (vccm)	YAG Power (V)	Incand. Conc. (#/cc)	Sheath Flow Set (vccm)	Sheath Flow Read (vccm)	YAG Crystal Temp (C)	YAG Heat Sink Temp (C)	Chamber Temp (C)	Chamber Pressure (mBar)	Pump Diode Power (V)	Duty Cycle (%)	Timestamp	Elapsed Time	Error Code	Electronics Temp (C)	Aux Input 0 (V)	Sheath Flow Read (sccm)	Purge Flow Read (sccm)	Chan 0 HV (V)	Aux Input 1 (V)	Aux Input 2 (V)	Chan 3 HV (V)	Purge Flow Read (vccm)	Purge Flow Set (vccm)	Exhaust Valve Set (Volts)	Sheath Flow Set (sccm)	Scatter. Conc. (#/cc)	Primary Threshold	Secondary Threshold	Num of Buffers	Num of Particles	Num Written to File	Num in File	Laser Current (mA)	Laser Curr Setpoint (mA)	Laser Voltage (V)	Laser Temp (C)	Laser TEC Temp (C)	Laser TEC Temp Setpoint	Laser TEC Current (mA)'
    display_names = header.split('\t')
    col_names = 'time,sample_flow_set_vccm,sample_flow_LFE_vccm,yag_power,incand_conc,sheath_flow_set_vccm,sheath_flow_read_vccm,yag_crystal_temp,yag_heat_sink_temp,chamber_temp,chamber_pressure,pump_diode_power,duty_cycle,timestamp,elapsed_time,error_code,electronics_temp,aux_input_0,sheath_flow_read_sccm,purge_flow_read_sccm,chan_0_hv,aux_input_1,aux_input_2,chan_3_hv,purge_flow_read_vccm,purge_flow_set_vccm,exhaust_valve_set,sheath_flow_set_sccm,scatter_conc,primary_threshold,secondary_threshold,num_of_buffers,num_of_particles,num_written_to_file,num_in_file,laser_current,laser_curr_setpoint,laser_voltage,laser_temp,laser_TEC_temp,laser_TEC_temp_set_point,laser_TEC_current'.split(',')

    # 默认值，为保持完整性
    defaults_str = '36576.750	120.000	117.593	3.960	506.678	1000.000	1002.733	56.672	32.708	32.515	931.173	1.809	100.000	3.61291E+9	61.4375	0	37.529923	0.002441	823.486328	252.075195	278.930664	0.002441	0.003052	376.327515	306.943897	246.746136	2.154847	822.487121	159.426854	-26668	-29394	5	1337	1337	42403	1948	1950	1.84	37.84	32.119999	32	531'
    
    data_write_formats = ['.3f']*13+['.5e','.4f','d']+['.6f']*13+['d']*8+['.2f']*2+['.6f']+['d']*2
    data_read_formats = [format[-1] for format in data_write_formats]

    # data types
    data_types = dict(zip(col_names, data_read_formats))

    # selected cols
    selected_cols = [col.strip() for col in 'incand_conc,scatter_conc'.split(',') ]

    # 生成格式化字符串
    line_write_formatter=sep.join([f'{{{col_name}:{format}}}' for col_name,format in zip(col_names,data_write_formats)])
    logger.info(line_write_formatter)

    line_read_formatter=sep.join([f'{{{col_name}:{format}}}' for col_name,format in zip(col_names,data_write_formats)])
    logger.info(line_read_formatter)

    # 简单测试
    parse_result = parse.parse(line_read_formatter,defaults_str)
    logger.info(parse_result)
    if parse_result is None:
        raise RuntimeError('Something go wrong!')

    # 默认值
    data_dict_defaults = parse_result.named
    
    # 建立设备连接
    TBD = TBDeviceMqttClient(host, port, token)
    TBD.connect()
    logger.info('mqtt server connected!')

    # 可以解析nan的parse自定义标签
    @parse.with_pattern(r'([+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?)|nan')
    def parse_float_with_nan(text):
        return float(text)
    parse.parse('{:float_with_nan}','nan',dict(float_with_nan=parse_float_with_nan))

    for line in tailhead.follow_path(target_log_file,encoding='utf-8'):
        if line is not None:
            logger.debug(f"readline: {line}")
            # 解析
            parse_result = parse.parse(line_read_formatter, line)
            if parse_result is None:
                logger.debug('not a valid data line')
                continue 
            data_line_dict = parse_result.named

            data_dict = {'ts':-1,'values':{}}
            # 时间解析
            # 假设是UTC时间，如果是北京时间需要调整
            today_ts = time.mktime(datetime.date.today().timetuple()) 
            time_ts = today_ts+data_line_dict['time']
            data_dict['ts'] = int(time_ts*1000) # 转换为ms数

            # 数据抽取
            data_dict['values'] = {col:data_line_dict.get(col,-99999) for col in selected_cols} # 如果没有数据，取-99999
            data_dict['values'] = {k:v if not isnan(v) else -99999.99 for k,v in data_dict['values'].items()} # 如果是nan，取-99999.99

            logger.info(f'data_dict={data_dict}')

            # 上传
            TBD.send_telemetry(data_dict)
            time.sleep(delay_time)
        else:
            logger.info('sleep.')
            time.sleep(delay_time)

if __name__ == "__main__":
    fire.Fire(main)
    # e.g
    # python demo_tail_log_upload.py --DELAY 0.5 --LOG_FILE your_file.log